using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace mp.Scanner
{
	public class FSAs
	{
		// -- Constructor for the FSAs class
		public FSAs()
		{
			reserved.Add("and", Token.mp_and);
			reserved.Add("begin", Token.mp_begin);
			reserved.Add("div", Token.mp_div);
			reserved.Add("do", Token.mp_do);
			reserved.Add("downto", Token.mp_downto);
			reserved.Add("else", Token.mp_else);
			reserved.Add("end", Token.mp_end);
			reserved.Add("fixed", Token.mp_fixed);
			reserved.Add("float", Token.mp_float);
			reserved.Add("for", Token.mp_for);
			reserved.Add("function", Token.mp_function);
			reserved.Add("if", Token.mp_if);
			reserved.Add("integer", Token.mp_integer);
			reserved.Add("mod", Token.mp_mod);
			reserved.Add("not", Token.mp_not);
			reserved.Add("or", Token.mp_or);
			reserved.Add("procedure", Token.mp_procedure);
			reserved.Add("program", Token.mp_program);
			reserved.Add("read", Token.mp_read);
			reserved.Add("repeat", Token.mp_repeat);
			reserved.Add("then", Token.mp_then);
			reserved.Add("to", Token.mp_to);
			reserved.Add("until", Token.mp_until);
			reserved.Add("var", Token.mp_var);
			reserved.Add("while", Token.mp_while);
			reserved.Add("write", Token.mp_write);
		}
		
		public string Scan_EOF(PositioningReader s){
			currentLexeme ="";
			string token = "";
			
			token = Token.mp_eof;
			currentLexeme = s.Read().ToString();		
			return token;
		}
		
		#region Simple FSAs
		
		public string Scan_Comma(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == ','){
				currentLexeme += (char) s.Read();
				token = Token.mp_comma;
			}
			return token;
		}
		
		public string Scan_Equal(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '='){
				currentLexeme += (char) s.Read();
				token = Token.mp_equal;
			}
			return token;
		}
		
		public string Scan_LParen(PositioningReader s)
		{	
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '('){
				currentLexeme += (char) s.Read();
				token = Token.mp_lparen;
			}
			return token;
		}
		
		public string Scan_Minus(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '-'){
				currentLexeme += (char) s.Read();
				token = Token.mp_minus;
			}
			return token;
		}
		
		public string Scan_Period(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '.'){
				currentLexeme += (char) s.Read();
				token = Token.mp_period;
			}
			return token;
		}
		
		public string Scan_Plus(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '+'){
				currentLexeme += (char) s.Read();
				token = Token.mp_plus;
			}
			return token;
		}
		
		public string Scan_RParen(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == ')'){
				currentLexeme += (char) s.Read();
				token = Token.mp_rparen;
			}
			return token;
		}
		
		public string Scan_Scolon(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == ';'){
				currentLexeme += (char) s.Read();
				token = Token.mp_scolon;
			}
			return token;
		}
		
		public string Scan_Times(PositioningReader s){
			currentLexeme = "";
			string token ="";
			
			if((char) s.Peek() == '*'){
				currentLexeme += (char) s.Read();
				token = Token.mp_times;
			}
			return token;
		}
		
		#endregion Simple FSAs
		
		#region Mediocre FSAs
		
		public string Scan_Assign(PositioningReader s){
			currentLexeme ="";
			string token = "";
			
			bool done = false;
			//Set start state
			State state = State.s0;
			while(!done){
				switch(state){
					case State.s0:
						switch((char) s.Peek()){
							case ':':
								state = State.s1;
								currentLexeme = currentLexeme + (char)s.Read();
								break;
						}
						break;
					
					case State.s1:
						switch((char) s.Peek()){
							//assign_op token has been scanned; scanning stops
							case '=':
								state = State.s2;
								break;
							//colon token and one extra character where scanned - handle error
							default:
								token = Token.mp_colon;
								done = true;
								break;
						}
						break;
					//an assignment operator has been scanned
					case State.s2:
						currentLexeme += (char) s.Read();
						token = Token.mp_assign;
						done = true;
						break;
				}
			}
			return token;
		}
		
		public string Scan_GEqual(PositioningReader s){
			currentLexeme ="";
			string token = "";
			bool done = false;
			State state = State.s0;
			
			while(!done){
				switch(state){
					case State.s0:
						if((char) s.Peek() == '>'){
							state = State.s1;
							currentLexeme = currentLexeme + (char)s.Read();
						}
						break;
					case State.s1:
						if((char) s.Peek() == '='){
							state = State.s2;
							currentLexeme = currentLexeme + (char)s.Read();
						} else {
							token = Token.mp_gthan;
							done = true;
						}
						break;
					case State.s2:
						currentLexeme += (char) s.Read();
						token = Token.mp_gequal;
						done = true;
						break;
				}
			}
			return token;
		}
		
		public string Scan_LEqual(PositioningReader s){
			currentLexeme ="";
			string token = "";
			bool done = false;
			State state = State.s0;
			
			while(!done){
				switch(state){
					case State.s0:
						if((char) s.Peek() == '<'){
							state = State.s1;
							currentLexeme = currentLexeme + (char)s.Read();
						}
						break;
					case State.s1:
						switch((char) s.Peek()){
							//assign_op token has been scanned; scanning stops
							case '=':
								state = State.s2;
								break;
							case '>':
								state = State.s3;
								break;
							//colon token and one extra character where scanned - handle error
							default:
								token = Token.mp_lthan;
								done = true;
								break;
						}
						break;
					case State.s2:
						currentLexeme += (char) s.Read();
						token = Token.mp_lequal;
						done = true;
						break;
					case State.s3:
						currentLexeme += (char) s.Read();
						token = Token.mp_nequal;
						done = true;
						break;
				}
			}
			return token;
		}
		
		#endregion Mediocre FSAs
		
		#region Complex FSAs
		
		public string Scan_Comment(PositioningReader s){
			currentLexeme = "";
			string token = "";
			
			bool done = false;
			//Set start state
			State state = State.s0;
			while(!done){
				switch(state){
					case State.s0:
						if((char) s.Peek() == '{'){
							s.Read();
							state = State.s1;
						}
						break;					
					case State.s1:
						if(s.Peek() < 0)
						{
							done = true;
							token = Token.mp_run_comment;
						}
						else if((char)s.Read() == '}'){
							state = State.s2;
						}						
						break;						
					case State.s2:
						token ="MP_COMMENT";
						done = true;				
						break;
				}
			}
			
			return token;
		}
		
		public string Scan_Identifier(PositioningReader pr){
			currentLexeme = "";
			string token = "";
			
			bool done = false;
			//Set start state
			State state = State.s0;
			while(!done){
				switch(state){
					case State.s0:
						if(Char.IsLetter((char) pr.Peek())){
							state = State.s1;
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else if(pr.Peek() == '_')
						{
							state = State.s2;
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else
						{
							token = Token.mp_error;
							done = true;
						}
						break;					
					case State.s1:
						if(Char.IsLetterOrDigit((char) pr.Peek())){
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else if(pr.Peek() == '_')
						{
							state = State.s2;
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else
						{
							token = Token.mp_identifier;
							done = true;
						}
						break;
					case State.s2:
						if(Char.IsLetterOrDigit((char) pr.Peek())){
							state = State.s1;
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else if(pr.Peek() == '_')
						{
							//Invalid ID
							currentLexeme = currentLexeme + (char)pr.Read();
							token = Token.mp_error;
							state = State.s3;
						}
						else
						{
							token = Token.mp_error;
							done = true;
						}
						break;
					case State.s3:
						if(Char.IsLetterOrDigit((char) pr.Peek()) || pr.Peek() == '_'){
							currentLexeme = currentLexeme + (char)pr.Read();
						}
						else
						{
							done = true;
						}
						break;
				}
			}
			
			if(!token.Equals(Token.mp_error)){
				//search for reserved word
				var temp = currentLexeme.ToLower();
				if(reserved.ContainsKey(temp))
					token = reserved[temp];
			}
			
			return token;
		}
		
		public string Scan_Number(PositioningReader pr){
			currentLexeme = "";
			string token = "";
			
			bool done = false;
			//Set start state
			State state = State.s0;
			while(!done){
				switch(state){
					case State.s0:
						if(char.IsDigit((char) pr.Peek()))
						{
							currentLexeme += (char) pr.Read();
						}
						else //if ((char)pr.Peek() == '\r' ||(char)pr.Peek() == ' ' || (char)pr.Peek() == '\n' || (char)pr.Peek() == '\t' || (char)pr.Peek() == '{')
						{
							done = true;
							token = Token.mp_integer_lit;
						}
						//else
						//{
							//invalid number
						//	currentLexeme = currentLexeme + (char) pr.Read();
						//	done = true;
						//	token = Token.mp_error;
						//}
						break;											
				}
			}			
			return token;
		}
		
		#endregion Complex FSAs
		
		#region properties
		
		public string currentLexeme;
		Dictionary<string, string> reserved = new Dictionary<string, string>();
		
		#endregion properties
	}
}

